import VSelect from '@/vuego/components/v-select/v-select';
import VOption from '@/vuego/components/v-select/v-option';
import Locale from '@/vuego/mixins/locale';
import Pager from './pager';

export default {
  name: 'VPagination',
  props: {
    pageSize: {
      type: Number,
      default: 10,
    },
    small: Boolean,
    total: Number,
    pageCount: Number,
    currentPage: {
      type: Number,
      default: 1,
    },
    layout: {
      default: 'prev, pager, next, jumper, ->, total',
    },
    pageSizes: {
      type: Array,
      default() {
        return [10, 20, 30, 40, 50, 100];
      },
    },
  },
  data() {
    return {
      internalCurrentPage: 1,
      internalPageSize: 0,
    };
  },

  render() {
    const template = <div class='v-pagination'></div>;
    template.children = [];
    const layout = this.layout || '';
    if (!layout) return undefined;
    const TEMPLATE_MAP = {
      prev: <prev></prev>,
      jumper: <jumper></jumper>,
      pager: <pager
          currentPage={ this.internalCurrentPage }
          pageCount={ this.internalPageCount }
          on-change={ this.handleCurrentChange }>
        </pager>,
      next: <next></next>,
      sizes: <sizes pageSizes={ this.pageSizes }></sizes>,
      slot: <my-slot></my-slot>,
      total: <total></total>,
    };
    const components = layout.split(',').map(item => item.trim());
    const rightWrapper = <div class="v-pagination__rightwrapper"></div>;
    let haveRightWrapper = false;

    if (this.small) {
      template.data.class += ' v-pagination--small';
    }

    components.forEach((compo) => {
      if (compo === '->') {
        haveRightWrapper = true;
        return;
      }

      if (!haveRightWrapper) {
        template.children.push(TEMPLATE_MAP[compo]);
      } else {
        rightWrapper.children.push(TEMPLATE_MAP[compo]);
      }
    });

    if (haveRightWrapper) {
      template.children.unshift(rightWrapper);
    }

    return template;
  },

  components: {
    MySlot: {
      render() {
        return (
          this.$parent.$slots.default
          ? this.$parent.$slots.default[0]
          : ''
        );
      },
    },
    Prev: {
      render() {
        return (
          <button
            type="button"
            class={['btn-prev', { disabled: this.$parent.internalCurrentPage <= 1 }]}
            on-click={ this.$parent.prev }>
            <i class="v-icon v-icon-arrow-left"></i>
          </button>
        );
      },
    },

    Next: {
      render() {
        return (
          <button
            type="button"
            class={[
              'btn-next',
              { disabled: this.$parent.internalCurrentPage === this.$parent.internalPageCount
                  || this.$parent.internalPageCount === 0 },
            ]}
            on-click={ this.$parent.next }>
            <i class="v-icon v-icon-arrow-right"></i>
          </button>
        );
      },
    },

    Sizes: {
      mixins: [Locale],
      props: {
        pageSizes: Array,
      },
      watch: {
        pageSizes: {
          immediate: true,
          handler(value) {
            if (Array.isArray(value)) {
              this.$parent.internalPageSize = value.indexOf(this.$parent.pageSize) > -1
                ? this.$parent.pageSize
                : this.pageSizes[0];
            }
          },
        },
      },

      render() {
        return (
          <span class="v-pagination__sizes">
            <v-select
              value={ this.$parent.internalPageSize }
              on-input={ this.handleChange }>
              {
                this.pageSizes.map(item =>
                  <v-option
                    value={ item }
                    label={ `${item} ${this.t('vuego.pagination.pagesize')}` }>
                  </v-option>,
                )
              }
            </v-select>
          </span>
        );
      },

      components: {
        VSelect,
        VOption,
      },

      methods: {
        handleChange(val) {
          if (val !== this.$parent.internalPageSize) {
            val = parseInt(val, 10);
            this.$parent.internalPageSize = val;
            this.$parent.$emit('size-change', val);
          }
        },
      },
    },

    Jumper: {
      mixins: [Locale],
      data() {
        return {
          oldValue: null,
        };
      },
      methods: {
        handleFocus(event) {
          this.oldValue = event.target.value;
        },
        handleBlur({ target }) {
          this.reassignMaxValue(target);
        },
        handleKeyUp(event) {
          const key = event.key || '';
          const keyCode = event.keyCode || '';
          if ((key && key === 'Enter') || (keyCode && keyCode === 13)) {
            this.reassignMaxValue(event.target);
            this.handleChange({ target: event.target });
          }
        },
        handleChange({ target }) {
          this.$parent.internalCurrentPage = this.$parent.getValidCurrentPage(target.value);
          this.oldValue = null;
        },
        reassignMaxValue(target) {
          if (+target.value > this.$parent.internalPageCount) {
            target.value = this.$parent.internalPageCount;
          }
        },
      },

      render() {
        return (
          <span class="v-pagination__jump">
            { this.t('vuego.pagination.goto') }
            <input
              class="v-pagination__editor"
              type="number"
              min={ 1 }
              max={ this.$parent.internalPageCount }
              value={ this.$parent.internalCurrentPage }
              domProps-value={ this.$parent.internalCurrentPage }
              on-change={ this.handleChange }
              on-focus={ this.handleFocus }
              on-blur={ this.handleBlur }
              on-keyup={ this.handleKeyUp }
              number/>
            { this.t('vuego.pagination.pageClassifier') }
          </span>
        );
      },
    },

    Total: {
      mixins: [Locale],
      render() {
        return (
          typeof this.$parent.total === 'number'
            ? <span class="v-pagination__total">{ this.t('vuego.pagination.total', { total: this.$parent.total }) }</span>
            : ''
        );
      },
    },
    Pager,
  },

  methods: {
    handleCurrentChange(val) {
      this.internalCurrentPage = this.getValidCurrentPage(val);
    },

    prev() {
      const newVal = this.internalCurrentPage - 1;
      this.internalCurrentPage = this.getValidCurrentPage(newVal);
    },

    next() {
      const newVal = this.internalCurrentPage + 1;
      this.internalCurrentPage = this.getValidCurrentPage(newVal);
    },

    getValidCurrentPage(value) {
      value = parseInt(value, 10);

      const havePageCount = typeof this.internalPageCount === 'number';

      let resetValue;
      if (!havePageCount) {
        if (isNaN(value) || value < 1) resetValue = 1;
      } else if (value < 1) {
        resetValue = 1;
      } else if (value > this.internalPageCount) {
        resetValue = this.internalPageCount;
      }

      if (resetValue === undefined && isNaN(value)) {
        resetValue = 1;
      } else if (resetValue === 0) {
        resetValue = 1;
      }

      return resetValue === undefined ? value : resetValue;
    },
  },

  computed: {
    internalPageCount() {
      if (typeof this.total === 'number') {
        return Math.ceil(this.total / this.internalPageSize);
      } else if (typeof this.pageCount === 'number') {
        return this.pageCount;
      }
      return null;
    },
  },

  watch: {
    currentPage: {
      immediate: true,
      handler(val) {
        this.internalCurrentPage = val;
      },
    },

    pageSize: {
      immediate: true,
      handler(val) {
        this.internalPageSize = val;
      },
    },

    internalCurrentPage(newVal, oldVal) {
      newVal = parseInt(newVal, 10);

      /* istanbul ignore if */
      if (isNaN(newVal)) {
        newVal = oldVal || 1;
      } else {
        newVal = this.getValidCurrentPage(newVal);
      }

      if (newVal !== undefined) {
        this.$nextTick(() => {
          this.internalCurrentPage = newVal;
          if (oldVal !== newVal) {
            this.$emit('update:currentPage', newVal);
            this.$emit('current-change', this.internalCurrentPage);
          }
        });
      } else {
        this.$emit('update:currentPage', newVal);
        this.$emit('current-change', this.internalCurrentPage);
      }
    },

    internalPageCount(newVal) {
      /* istanbul ignore if */
      const oldPage = this.internalCurrentPage;
      if (newVal > 0 && oldPage === 0) {
        this.internalCurrentPage = 1;
      } else if (oldPage > newVal) {
        this.internalCurrentPage = newVal === 0 ? 1 : newVal;
      }
    },
  },
};
